extern crate syslog;
extern crate log;

use std::process;
use std::sync::{Arc, Mutex};

use syslog::{Facility, Formatter3164, LoggerBackend, Logger};
use log::{LevelFilter, Metadata, Record, Level};

pub struct HotCureLogger;

impl HotCureLogger {
    pub fn new(name: &str, level: LevelFilter) {
        let formatter = Formatter3164 {
            facility: Facility::LOG_USER,
            hostname: None,
            process: name.into(),
            pid: process::id(),
        };

        let logger = syslog::unix(formatter).expect("Failed to connect to syslog");
        log::set_boxed_logger(Box::new(SyslogLogger::new(logger)))
            .map(|()| log::set_max_level(level)).expect("Failed to set log level filter");
    }
}

pub struct SyslogLogger {
    logger: Arc<Mutex<Logger<LoggerBackend, Formatter3164>>>,
}

impl SyslogLogger {
    pub fn new(logger: Logger<LoggerBackend, Formatter3164>) -> SyslogLogger {
        SyslogLogger {
            logger: Arc::new(Mutex::new(logger)),
        }
    }
}

#[allow(unused_variables, unused_must_use)]
impl log::Log for SyslogLogger {
    fn enabled(&self, metadata: &Metadata) -> bool {
        metadata.level() <= log::max_level() && metadata.level() <= log::STATIC_MAX_LEVEL
    }

    fn log(&self, record: &Record) {
        let message = format!("{}[{}]: {}", record.file().unwrap_or(""),
                                            record.line().unwrap_or(0),
                                            record.args());
        let mut logger = self.logger.lock().unwrap();
        match record.level() {
            Level::Error => logger.err(message),
            Level::Warn => logger.warning(message),
            Level::Info => logger.info(message),
            Level::Debug => logger.debug(message),
            Level::Trace => logger.debug(message),
        };
    }

    fn flush(&self) {}
}
